package com.dc.base.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author 冰柠檬dc
 * 反射工具类
 */
public class ReflectUtil {

    /**
     * 获取类属性（包含私有以及受保护的，父类也会检索）
     *
     * @param clazz     类
     * @param fieldName 属性名称
     * @return 属性
     */
    public static Field getField(Class<?> clazz, String fieldName) {
        Field field = null;
        try {
            // getField 只能获取public的，包括从父类继承来的字段
            field = clazz.getField(fieldName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        if (field == null) {
            try {
                // getDeclaredField 可以获取本类所有的字段，包括private的，但是不能获取继承来的字段,除非加上setAccessible(true)
                field = clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        if (field == null) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                field = getField(superClass, fieldName);
            }
        }
        return field;
    }

    /**
     * 获取属性的值
     *
     * @param object    对象
     * @param fieldName 属性名
     * @return 属性值
     */
    public static Object getFieldValue(Object object, String fieldName) {
        Object value = null;
        if (object != null) {
            Field field = getField(object.getClass(), fieldName);
            if (field != null) {
                field.setAccessible(true);
                try {
                    value = field.get(object);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return value;
    }

    /**
     * 获取静态属性值
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @return 属性值
     */
    public static Object getStaticFieldValue(Class<?> clazz, String fieldName) {
        Field field = getField(clazz, fieldName);
        Object value = null;
        if (field != null) {
            field.setAccessible(true);
            if (isStatic(field)) {
                try {
                    value = field.get(null);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return value;
    }

    /**
     * 设置属性值
     *
     * @param object    对象
     * @param fieldName 属性名
     * @param value     值
     */
    public static void setFieldValue(Object object, String fieldName, Object value) {
        if (object != null) {
            Field field = getField(object.getClass(), fieldName);
            if (field != null) {
                field.setAccessible(true);
                try {
                    field.set(object, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 设置静态属性值
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @param value     新值
     */
    public static void setStaticFieldValue(Class<?> clazz, String fieldName, Object value) {
        Field field = getField(clazz, fieldName);
        if (field != null) {
            field.setAccessible(true);
            if (isStatic(field)) {
                try {
                    field.set(null, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 是否静态（方法、属性。。。）
     *
     * @param field 要判断的对象
     * @return 是否
     */
    public static boolean isStatic(Object field) {
        return Modifier.isStatic((Integer) invokeMethod(field, "getModifiers", (Object[]) null));
    }

    /**
     * 是否不可变/覆写（方法、属性。。。）
     *
     * @param field 要判断的对象
     * @return 是否
     */
    public static boolean isFinal(Object field) {
        return Modifier.isFinal((Integer) invokeMethod(field, "getModifiers", (Object[]) null));
    }

    /**
     * 是否公共（方法、属性。。。）
     *
     * @param field 要判断的对象
     * @return 是否
     */
    public static boolean isPublic(Object field) {
        return Modifier.isPublic((Integer) invokeMethod(field, "getModifiers", (Object[]) null));
    }

    /**
     * 是否私有（方法、属性。。。）
     *
     * @param field 要判断的对象
     * @return 是否
     */
    public static boolean isPrivate(Object field) {
        return Modifier.isPrivate((Integer) invokeMethod(field, "getModifiers", (Object[]) null));
    }

    /**
     * 是否受保护（方法、属性。。。）
     *
     * @param field 要判断的对象
     * @return 是否
     */
    public static boolean isProtected(Object field) {
        return Modifier.isProtected((Integer) invokeMethod(field, "getModifiers", (Object[]) null));
    }

    /**
     * 获取类方法（包含私有以及受保护的，父类也会检索）
     *
     * @param clazz      类
     * @param methodName 方法名
     * @param var        方法的参数类型
     * @return 方法对象
     */
    public static Method getMethod(Class<?> clazz, String methodName, Class<?>... var) {
        Method method = null;
        try {
            method = clazz.getMethod(methodName, var);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (method == null) {
            try {
                method = clazz.getDeclaredMethod(methodName, var);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        if (method == null) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                method = getMethod(superClass, methodName, var);
            }
        }
        return method;
    }

    /**
     * 执行类方法
     *
     * @param object     类对象
     * @param methodName 方法名
     * @param argsType   参数类型
     * @param var        参数
     * @return 执行结果
     */
    public static Object invokeMethod(Object object, String methodName, Class<?>[] argsType, Object... var) {
        Method method = getMethod(object.getClass(), methodName, argsType);
        Object result = null;
        if (method != null) {
            method.setAccessible(true);
            try {
                result = method.invoke(object, var);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 执行类方法
     *
     * @param object     类对象
     * @param methodName 方法名
     * @param var        参数
     * @return 执行结果
     */
    public static Object invokeMethod(Object object, String methodName, Object... var) {
        Class<?>[] args = null;
        if (var != null) {
            args = new Class[var.length];
            for (int i = 0; i < var.length; i++) {
                args[i] = var[i].getClass();
            }
        }
        Method method = getMethod(object.getClass(), methodName, args);
        Object result = null;
        try {
            if (method != null) {
                method.setAccessible(true);
                result = method.invoke(object, var);
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 执行静态方法
     *
     * @param clazz      类
     * @param methodName 方法名
     * @param var        参数
     * @return 执行结果
     */
    public static Object invokeStaticMethod(Class<?> clazz, String methodName, Object... var) {
        Class<?>[] args = null;
        if (var != null) {
            args = new Class[var.length];
            for (int i = 0; i < var.length; i++) {
                args[i] = var[i].getClass();
            }
        }
        Method method = getMethod(clazz, methodName, args);
        Object result = null;
        if (method != null) {
            if (isStatic(method)) {
                method.setAccessible(true);
                try {
                    result = method.invoke(null, var);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 获取类实例（无参数构造函数）
     *
     * @param clazz 类
     * @param <T>   泛型类型
     * @return 类实例
     */
    public static <T> T getClassInstance(Class<T> clazz) {
        return getClassInstance(clazz, (Class<?>) null, null);
    }

    /**
     * 获取类实例（一个参数构造函数）
     *
     * @param clazz         类
     * @param parameterType 构造函数参数类型
     * @param arg           构造函数参数值
     * @param <T>           泛型类型
     * @return 类实例
     */
    public static <T> T getClassInstance(Class<T> clazz, Class<?> parameterType, Object arg) {
        return getClassInstance(clazz, new Class[]{parameterType}, new Object[]{arg});
    }

    /**
     * 获取类实例（多个参数构造函数）
     *
     * @param clazz          类
     * @param parameterTypes 构造函数参数类型
     * @param args           构造函数参数值
     * @param <T>            泛型类型
     * @return 类实例
     */
    public static <T> T getClassInstance(Class<T> clazz, Class<?>[] parameterTypes, Object[] args) {
        T t;
        try {
            if (parameterTypes == null || args == null) {
                t = clazz.getConstructor().newInstance();
            } else {
                t = clazz.getConstructor(parameterTypes).newInstance(args);
            }
            return t;
        } catch (InvocationTargetException | IllegalAccessException | InstantiationException | NoSuchMethodException e) {
            return null;
        }

    }
}
